package com.yuzhihao.writejvm.read;

import com.yuzhihao.writejvm.attributes.*;
import com.yuzhihao.writejvm.attributes.runtimeva.*;
import com.yuzhihao.writejvm.attributes.runtimevta.*;
import com.yuzhihao.writejvm.attributes.stack.*;
import com.yuzhihao.writejvm.attributes.stack.verification.*;
import com.yuzhihao.writejvm.code.Operation;
import com.yuzhihao.writejvm.constant.*;
import com.yuzhihao.writejvm.format.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;

/**
 * 处理class 文件的工厂方法
 *
 * @author yzh
 * @date 2021年11月29日18:01:06
 */
public class ReadClassFileFatory {


    /**
     * 获取new数组类型枚举
     * @param value
     * @return
     */
    public static NewarrayTypeEnum newarray_type_enum(int value){
        return Arrays.stream(NewarrayTypeEnum.values()).filter(e -> e.getValue() == value).findFirst().orElseThrow(() -> new RuntimeException("枚举入参错误！"));
    }

    /**
     * 获取指令实例
     * @param value
     * @return
     */
    public static Operation frame_instance(int value){
        Constructor<?>[] constructors = FormsEnum.instance(value).getClazz().getConstructors();
        for (Constructor<?> constructor : constructors) {
            constructor.setAccessible(true);
            try {
                if (constructor.getParameterCount() == 0) {
                    Object o = constructor.newInstance();
                    if(o instanceof Operation){
                        return (Operation) o;
                    }
                }
            } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 获取栈映射框架实例
     * @param value
     * @return
     */
    public static StackMapFrame smf_instance(int value){
        StackMapFrameEnum eve = Arrays.stream(StackMapFrameEnum.values()).filter(e -> (e.getStart() <= value && value <= e.getEnd())).findFirst().orElseThrow(() -> new RuntimeException("枚举入参错误！"));
        switch (eve) {
            case same_frame:
                return new SameFrame();
            case same_locals_1_stack_item_frame:
                return new SameLocals1StackItemFrame();
            case same_locals_1_stack_item_frame_extended:
                return new SameLocals1StackItemFrameExtended();
            case chop_frame:
                return new ChopFrame();
            case same_frame_extended:
                return new SameFrameExtended();
            case append_frame:
                return new AppendFrame();
            case full_frame:
                return new FullFrame();
            default: return null;
        }
    }

    /**
     * 获取验证类型实例
     * @param value
     * @return
     */
    public static VerificationTypeInfo verification_instance(int value){
        VerificationTypeEnum eve = Arrays.stream(VerificationTypeEnum.values()).filter(e -> e.getValue() == value).findFirst().orElseThrow(() -> new RuntimeException("枚举入参错误！"));
        switch (eve) {
            case Top_variable_info:
                return new TopVariableInfo();
            case Integer_variable_info:
                return new IntegerVariableInfo();
            case Float_variable_info:
                return new FloatVariableInfo();
            case Null_variable_info:
                return new NullVariableInfo();
            case UninitializedThis_variable_info:
                return new UninitializedThisVariableInfo();
            case Object_variable_info:
                return new ObjectVariableInfo();
            case Uninitialized_variable_info:
                return new UninitializedVariableInfo();
            case Long_variable_info:
                return new LongVariableInfo();
            case Double_variable_info:
                return new DoubleVariableInfo();
            default: return null;
        }
    }

    /**
     * 获取运行时变量表类型
     *
     * @param item
     * @return
     */
    public static TypeAnnotation tt_instance(int item) {
        TargetTypeEnum eve = Arrays.stream(TargetTypeEnum.values()).filter(e -> e.getValue() == item).findFirst().orElseThrow(() -> new RuntimeException("枚举入参错误！"));
        switch (eve) {
            case class_or_interface:
            case method_or_constructor:
                return new TypeParameterTarget(item);
            case bound_class_or_interface:
            case bound_method_or_constructor:
                return new TypeParameterBoundTarget(item);
            case implements_extends:
                return new SupertypeTarget(item);
            case field:
            case return_method:
            case receiver_method_or_constructor:
                return new EmptyTarget(item);
            case formal_method_constructor_or_lambda:
                return new FormalParameterTarget(item);
            case throws_method_or_constructor:
                return new ThrowsTarget(item);
            case local:
            case resource:
                return new LocalvarTarget(item);
            case exception_parameter:
                return new CatchTarget(item);
            case instanceof_expression:
            case new_expression:
            case method_reference_expression_using_new:
            case method_reference_expression_using_identifier:
                return new OffsetTarget(item);
            case cast_expression:
            case constructor_invocation:
            case method_invocation:
            case constructor_new:
            case constructor_Identifier:
                return new TypeArgumentTarget(item);
            default:
                return new TypeAnnotation();
        }
    }

    /**
     * 获取运行时变量表元素实例
     *
     * @param item
     * @return
     */
    public static ElementValue ev_instance(char item) {
        ElementValueEnum eve = Arrays.stream(ElementValueEnum.values()).filter(e -> e.getTag() == item).findFirst().orElseThrow(() -> new RuntimeException("枚举入参错误！"));
        switch (eve) {
            case Enum:
                return new EnumConstValue(item);
            case Class:
                return new ClassInfoIndex(item);
            case Annotation:
                return new Annotation(item);
            case Array:
                return new ArrayValue(item);
            default:
                return new ConstValueIndex(item);
        }
    }

    /**
     * 获取属性类型解析实例
     *
     * @param aname
     * @return
     */
    public static Attributes attributes_instance(String aname) {
        switch (aname) {
            case AttributesType.ConstantValue:
                return new ConstantValueAttribute(aname);
            case AttributesType.Code:
                return new Code(aname);
            case AttributesType.StackMapTable:
                return new StackMapTableAttribute(aname);
            case AttributesType.Exceptions:
                return new ExceptionsAttribute(aname);
            case AttributesType.InnerClasses:
                return new InnerClassesAttribute(aname);
            case AttributesType.EnclosingMethod:
                return new EnclosingMethodAttribute(aname);
            case AttributesType.Synthetic:
                return new SyntheticAttribute(aname);
            case AttributesType.Signature:
                return new SignatureAttribute(aname);
            case AttributesType.SourceFile:
                return new SourceFileAttribute(aname);
            case AttributesType.SourceDebugExtension:
                return new SourceDebugExtensionAttribute(aname);
            case AttributesType.LineNumberTable:
                return new LineNumberTableAttribute(aname);
            case AttributesType.LocalVariableTable:
                return new LocalVariableTableAttribute(aname);
            case AttributesType.LocalVariableTypeTable:
                return new LocalVariableTypeTableAttribute(aname);
            case AttributesType.Deprecated:
                return new DeprecatedAttribute(aname);
            case AttributesType.RuntimeVisibleAnnotations:
                return new RuntimeVisibleAnnotationsAttribute(aname);
            case AttributesType.RuntimeInvisibleAnnotations:
                return new RuntimeInvisibleAnnotationsAttribute(aname);
            case AttributesType.RuntimeVisibleParameterAnnotations:
                return new RuntimeVisibleParameterAnnotationsAttribute(aname);
            case AttributesType.RuntimeInvisibleParameterAnnotations:
                return new RuntimeInvisibleParameterAnnotationsAttribute(aname);
            case AttributesType.RuntimeVisibleTypeAnnotations:
                return new RuntimeVisibleTypeAnnotationsAttribute(aname);
            case AttributesType.RuntimeInvisibleTypeAnnotations:
                return new RuntimeInvisibleTypeAnnotationsAttribute(aname);
            case AttributesType.AnnotationDefault:
                return new AnnotationDefaultAttribute(aname);
            case AttributesType.BootstrapMethods:
                return new BootstrapMethodsAttribute(aname);
            case AttributesType.MethodParameters:
                return new MethodParametersAttribute(aname);
            default:
                return null;
        }
    }

    /**
     * 获取常量池类型解析实例
     *
     * @param value
     * @return
     */
    public static ConstantPool constant_pool_instance(int value, Map<String, ConstantPool> pools) {
        switch (value) {
            case ConstantType
                    .CONSTANT_Class:
                return new ConstantClassInfo(pools);
            case ConstantType
                    .CONSTANT_Fieldref:
                return new ConstantFieldrefInfo(pools);
            case ConstantType
                    .CONSTANT_Methodref:
                return new ConstantMethodrefInfo(pools);
            case ConstantType
                    .CONSTANT_InterfaceMethodref:
                return new ConstantInterfaceMethodrefInfo(pools);
            case ConstantType
                    .CONSTANT_String:
                return new ConstantStringInfo(pools);
            case ConstantType
                    .CONSTANT_Integer:
                return new ConstantIntegerInfo(pools);
            case ConstantType
                    .CONSTANT_Float:
                return new ConstantFloatInfo(pools);
            case ConstantType
                    .CONSTANT_Long:
                return new ConstantLongInfo(pools);
            case ConstantType
                    .CONSTANT_Double:
                return new ConstantDoubleInfo(pools);
            case ConstantType
                    .CONSTANT_NameAndType:
                return new ConstantNameAndTypeInfo(pools);
            case ConstantType
                    .CONSTANT_Utf8:
                return new ConstantUtf8Info(pools);
            case ConstantType
                    .CONSTANT_MethodHandle:
                return new ConstantMethodHandleInfo(pools);
            case ConstantType
                    .CONSTANT_MethodType:
                return new ConstantMethodTypeInfo(pools);
            case ConstantType
                    .CONSTANT_InvokeDynamic:
                return new ConstantInvokeDynamicInfo(pools);
            default:
                return null;
        }
    }

    /**
     * Method Type and Method Handle Resolution
     * <p>
     * 获取方法处理信息
     *
     * @param value
     * @return
     */
    public static MethodTypeResolutionEnum method_handle_instance(int value) {
        if (value == MethodTypeResolutionEnum.REF_getField.getValue()) {
            return MethodTypeResolutionEnum.REF_getField;
        } else if (value == MethodTypeResolutionEnum.REF_getStatic.getValue()) {
            return MethodTypeResolutionEnum.REF_getStatic;
        } else if (value == MethodTypeResolutionEnum.REF_putField.getValue()) {
            return MethodTypeResolutionEnum.REF_putField;
        } else if (value == MethodTypeResolutionEnum.REF_putStatic.getValue()) {
            return MethodTypeResolutionEnum.REF_putStatic;
        } else if (value == MethodTypeResolutionEnum.REF_invokeVirtual.getValue()) {
            return MethodTypeResolutionEnum.REF_invokeVirtual;
        } else if (value == MethodTypeResolutionEnum.REF_invokeStatic.getValue()) {
            return MethodTypeResolutionEnum.REF_invokeStatic;
        } else if (value == MethodTypeResolutionEnum.REF_invokeSpecial.getValue()) {
            return MethodTypeResolutionEnum.REF_invokeSpecial;
        } else if (value == MethodTypeResolutionEnum.REF_newInvokeSpecial.getValue()) {
            return MethodTypeResolutionEnum.REF_newInvokeSpecial;
        } else if (value == MethodTypeResolutionEnum.REF_invokeInterface.getValue()) {
            return MethodTypeResolutionEnum.REF_invokeInterface;
        }
        return null;
    }

}
